import Constent.FillConstent;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Features: 通用参数处理  tips paramter(K v)-->转换成 entity
 * @Date:
 * @Author: hihuzi  2018/6/14 10:18
 */
public class FillUtil implements FillFactory {

    /**
     * tips 对请求进行参数进行装填-->MAP
     *
     * @Author:hihuzi 2018/6/14 14:51
     */
    @Override
    public Map getParamsToMap(HttpServletRequest request) {

        return getParamsToMap(request, FillConstent.WhetherTheNullValueIsSaved);
    }

    /**
     * tips 对请求进行参数进行装填-->MAP strs 去掉没用的字段
     *
     * @param request
     * @param strs
     * @Author:hihuzi 2018/6/14 14:51
     */
    @Override
    public Map getParamsToMap(HttpServletRequest request, String... strs) {

        return getParamsToMap(request, FillConstent.DeleteSpecificFields, strs);
    }

    /**
     * tips 对MAP数据装填--> 对象
     *
     * @Author:hihuzi 2018/6/14 14:50
     */
    @Override
    public <T> T getMapToEntity(Map<String, String> maps, T t) throws Exception {

        return getMapToEntity(maps, t, FillConstent.WhetherTheNullValueIsSaved);
    }

    /**
     * tips 对请求进行参数进行装填--> 对象
     *
     * @Author:hihuzi 2018/6/14 14:50
     */
    @Override
    public <T> T getParamsToEntity(HttpServletRequest request, T t) throws Exception {

        return getParamsToEntity(request, t, FillConstent.WhetherTheNullValueIsSaved);
    }

    /**
     * tips tips 对MAP数据装填--> 对象
     *
     * @Author:hihuzi 2018/6/14 14:50
     */
    @Override
    public <T> T getMapToEntityDiff(Map map, T t) throws Exception {

        return getMapToEntityDiff(map, t, FillConstent.WhetherTheNullValueIsSaved);
    }

    /**
     * tips tips 对LIST数据装填--> 对象 针对数据库与实体类名有区别 value -->t
     *
     * @param list
     * @param t
     * @Author:hihuzi 2018/6/26 14:51
     */
    @Override
    public <T> List<T> getListToEntity(List<String> list, T t) throws Exception {

        return getListToEntity(list, t, FillConstent.SEQUENCE);
    }

    /**
     * tips tips 对LIST数据装填--> 对象 针对数据库与实体类名有区别 key-value -->t
     *
     * @Author:hihuzi 2018/6/26 14:51
     */
    @Override
    public <T> List<T> getListToEntitys(List<Map> maps, T t) throws Exception {

        return getListToEntitys(maps, t, FillConstent.Default);
    }
    //achieve 具体实现

    public Map getParamsToMap(HttpServletRequest request, FillConstent fillConstent) {

        Map map = new HashMap();
        Enumeration pars = request.getParameterNames();
        while (pars.hasMoreElements()) {
            String name = pars.nextElement().toString().trim();
            String value = request.getParameter(name);
            if (StrUtil.isNotNullAndEmpty(value)) {//tips 考虑是否是空值  null
                map.put(name, value);
            } else {
                if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                    map.put(name, value);
            }
        }
        return map;
    }

    public Map getParamsToMap(HttpServletRequest request, FillConstent fillConstent, String... strs) {

        Map map = new HashMap();
        List<String> exclude = Arrays.asList(strs);
        Enumeration pars = request.getParameterNames();
        while (pars.hasMoreElements()) {
            String name = pars.nextElement().toString().trim();
            String value = request.getParameter(name);
            if (!exclude.contains(name)) {//tips
                if (StrUtil.isNotNullAndEmpty(value)) {//tips 考虑是否是空值  null
                    map.put(name, value);
                } else {
                    if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                        map.put(name, value);
                }
            } else {
                if (!fillConstent.getDeleteFields()) {
                    if (StrUtil.isNotNullAndEmpty(value)) {//tips 考虑是否是空值  null
                        map.put(name, value);
                    } else {
                        if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                            map.put(name, value);
                    }
                }
            }
        }
        return map;
    }

    public <T> T getMapToEntity(Map<String, String> maps, T t, FillConstent fillConstent) throws Exception {

        Iterator iterator = maps.entrySet().iterator();
        Class<T> clazz = (Class<T>) t.getClass();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String names = String.valueOf(entry.getKey());
            String value = String.valueOf(entry.getValue());
            if (StrUtil.isNotNullOrEmpty(value.toString())) {//tips 考虑是否是空值  null
                injectionParameters(t, clazz, names, value, fillConstent);
            } else {
                if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                    injectionParameters(t, clazz, names, value, fillConstent);
            }
        }
        return t;
    }

    public <T> T getParamsToEntity(HttpServletRequest request, T t, FillConstent fillConstent) throws Exception {

        Enumeration pars = request.getParameterNames();
        Class<T> clazz = (Class<T>) t.getClass();
        while (pars.hasMoreElements()) {
            String names = pars.nextElement().toString().trim();
            String value = request.getParameter(names);
            if (StrUtil.isNotNullOrEmpty(value)) {//tips 考虑是否是空值  null
                injectionParameters(t, clazz, names, value, fillConstent);
            } else {
                if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                    injectionParameters(t, clazz, names, value, fillConstent);
            }
        }
        return t;
    }

    public <T> T getMapToEntityDiff(Map map, T t, FillConstent fillConstent) throws Exception {

        Iterator iterator = map.entrySet().iterator();
        Class<T> clazz = (Class<T>) t.getClass();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String names = String.valueOf(entry.getKey());
            String value = String.valueOf(entry.getValue());
            if (StrUtil.isNotNullOrEmpty(value, names)) {//tips 考虑是否是空值  null
                injectionParameters(t, clazz, names, value, fillConstent);
            } else {
                if (fillConstent.getWhetherSave())//tips  空值时是否存储 空字符串
                    injectionParameters(t, clazz, names, value, fillConstent);
            }
        }
        return t;
    }

    public <T> List<T> getListToEntitys(List<Map> maps, T t, FillConstent fillConstent) throws Exception {

        List<T> result = new ArrayList<>();
        List<String> fieldsMap = new ArrayList<>();
        List<Map> entityMaps = new ArrayList<>();
        Class<T> clazz = (Class<T>) t.getClass();
        //todo 遍历所有父类子类属性
        for (; clazz != Object.class; clazz = (Class<T>) clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                fieldsMap.add(fields[i].getName());
            }
        }
        for (Map map : maps) {
            Iterator iterator = map.entrySet().iterator();
            Map transition = new HashMap();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                String names = String.valueOf(entry.getKey());
                String value = String.valueOf(entry.getValue());
                if (StrUtil.isNotNullOrEmpty(value)) {
                    //tips name 处理大小写
                    for (String fields : fieldsMap) {
                        if (fields.toLowerCase().equalsIgnoreCase(names.replaceAll("_", "").toLowerCase())) {
                            transition.put(fields, value);
                        }
                    }
                }
            }
            entityMaps.add(transition);
        }
        for (Map map : entityMaps) {
            Object obj = t.getClass().newInstance();/*新建对象*/
            obj = getMapToEntityDiff(map, obj);
            result.add((T) obj);
        }
        return result;
    }

    //achieve 公共方法
    public <T> List<T> getListToEntity(List<String> list, T t, FillConstent fillConstent) throws Exception {

        List<T> result = new ArrayList<>();
        List<String> field = new ArrayList<>();
        List<String> fieldsMap = new ArrayList<>();
        List<Map> entityMaps = new ArrayList<>();
        Class<T> clazz = (Class<T>) t.getClass();
        //todo 遍历所有父类子类属性
        for (; clazz != Object.class; clazz = (Class<T>) clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                field.add(fields[i].getName());
            }
        }
        int i = 0;
        if (fillConstent != null) {
            Integer[] sort = fillConstent.getSort();
            for (Integer integer : sort) {//tips 最外层
                if (integer < field.size() && i <= field.size()) {//tips 实体 属性
                    fieldsMap.add(field.get(integer));//tips key
                } else {
                    fieldsMap.add("");
                }
                i++;
            }
        } else {//tips FillConstent 传值为空时
            fieldsMap = field;
        }

        Map transition = new HashMap();
        i = 0;
        for (String fields : fieldsMap) {//key
            if (i < list.size() && !fields.equals("")) {
                transition.put(fields, list.get(i));
                i++;
            }
        }
        entityMaps.add(transition);
        for (Map map : entityMaps) {
            Object obj = t.getClass().newInstance();/*新建对象*/
            obj = getMapToEntityDiff(map, obj, FillConstent.SEQUENCE);
            result.add((T) obj);
        }
        return result;
    }

    /**
     * 注入参数
     *
     * @title: nihao
     * @param: t
     * @param: clazz
     * @param: names
     * @param: value
     * @Author:hihuzi 2018/6/22 9:22
     */
    private static <T> void injectionParameters(T t, Class<T> clazz, String names, String value, FillConstent fillConstent) throws
            Exception {

        StringBuffer name = new StringBuffer();
        name.append("set").append(names.substring(0, 1).toUpperCase()).append(names.substring(1));
        Class<?> paramtertype = null;
        try {
            paramtertype = clazz.getDeclaredField(names).getType();
        } catch (NoSuchFieldException e) {
        }
        if (StrUtil.isNotNullOrEmptyEntrty(paramtertype)) {
            setParamter((T) t, (Class<T>) clazz, names, value, name, paramtertype, fillConstent);
        } else {
            //tips 父类遍历
            for (; clazz != Object.class; clazz = (Class<T>) clazz.getSuperclass()) {
                try {
                    paramtertype = clazz.getDeclaredField(names).getType();
                } catch (NoSuchFieldException e) {
                }
                if (StrUtil.isNotNullOrEmptyEntrty(paramtertype)) {
                    setParamter(t, clazz, names, value, name, paramtertype, fillConstent);
                }
            }

        }
    }

    private static <T> void setParamter(T t, Class<T> clazz, String names, String value, StringBuffer
            name, Class<?> paramtertype, FillConstent fillConstent) throws Exception {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Method method = clazz.getMethod(name.toString(), paramtertype);
        String fieldType = clazz.getDeclaredField(names).getType().getSimpleName();
        if (null != value && !value.equals("")) {
            if ("String".equals(fieldType)) {
                method.invoke(t, value);
            } else if ("Date".equals(fieldType)) {
                if (fillConstent.name().equals("SEQUENCE")) {
                    method.invoke(t, fillConstent.getSimpleDateFormat().parse(value));
                } else {
                    if (value.length() <= 10) value += " 00:00:00";
                    method.invoke(t, format.parse(value));
                }
            } else if ("char".equalsIgnoreCase(fieldType)) {
                method.invoke(t, value.toCharArray()[0]);
            } else if ("Byte".equalsIgnoreCase(fieldType) || "byte".equals(fieldType)) {
                method.invoke(t, Byte.valueOf(value));
            } else if ("Long".equalsIgnoreCase(fieldType) || "long".equals(fieldType)) {
                method.invoke(t, Long.parseLong(value));
            } else if ("Short".equals(fieldType) || "short".equals(fieldType)) {
                method.invoke(t, Short.parseShort(value));
            } else if ("Float".equals(fieldType) || "float".equals(fieldType)) {
                method.invoke(t, Float.parseFloat(value));
            } else if ("Double".equalsIgnoreCase(fieldType) || "double".equals(fieldType)) {
                method.invoke(t, Double.parseDouble(value));
            } else if ("Integer".equals(fieldType) || "int".equals(fieldType)) {
                method.invoke(t, Integer.parseInt(value));
            } else if ("Boolean".equalsIgnoreCase(fieldType) || "boolean".equals(fieldType)) {
                method.invoke(t, Boolean.parseBoolean(value));
            } else if ("BigDecimal".equalsIgnoreCase(fieldType)) {
                method.invoke(t, new BigDecimal(value));
            } else {
                System.out.println("类型错误" + fieldType);
            }
        } else {//tips 针对 value=null or value =""
            if (("String".equals(fieldType) && value.equals("")))
                method.invoke(t, value);
            else if (("int".equals(fieldType) || "float".equals(fieldType) || "long".equals(fieldType) || "double".equals(fieldType)) && value.equals(""))
                method.invoke(t, 0);
            else if ("boolean".equals(fieldType) && value.equals(""))
                method.invoke(t, false);
            else if ("short".equals(fieldType) && value.equals(""))
                method.invoke(t, (short) 0);
            else if ("byte".equals(fieldType) && value.equals(""))
                method.invoke(t, Byte.parseByte("0"));
            else if ("char".equals(fieldType) && value.equals("")) {
                //tips 不做处理
            } else
                method.invoke(t, new Object[]{null});
        }
    }

    /**
     * 随机填充
     *
     * @Author:hihuzi 2018/6/23 9:28
     */
    public static <T> T getFillEntity(T t) throws Exception {

        Class<T> clazz = (Class<T>) t.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            String names = String.valueOf(field.getName());
            String value = String.valueOf(UUID.randomUUID().toString().substring(0, 3));
            injectionParameters(t, clazz, names, value, FillConstent.Default);
        }
        return t;
    }

}
